package ohc.login

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.fabricmc.loader.api.FabricLoader
import java.io.File
import java.util.*

/**
 * 玩家数据管理类，用于存储玩家与 API 账号的绑定关系
 */
object PlayerDataManager {
    private val gson: Gson = GsonBuilder().setPrettyPrinting().create()
    private val dataFile: File = FabricLoader.getInstance().configDir.resolve("ohc_login_players.json").toFile()
    
    // 存储玩家 UUID 与 API 账号的绑定关系
    // Key: 玩家 UUID, Value: PlayerData
    private val playerBindings: MutableMap<String, PlayerData> = mutableMapOf()
    
    // 存储欢迎词
    // Key: API UID, Value: 欢迎消息
    private val welcomeMessages: MutableMap<String, String> = mutableMapOf()
    
    // 存储临时账号（未绑定但设置了备用密码的玩家）
    // Key: 玩家 UUID, Value: 备用密码哈希
    private val tempAccounts: MutableMap<String, String> = mutableMapOf()
    
    // 存储有存档权限的玩家
    // Key: 玩家名（小写）
    private val backupPermissions: MutableSet<String> = mutableSetOf()
    
    /**
     * 玩家数据类
     */
    data class PlayerData(
        val uuid: String,           // 玩家 UUID
        val apiUid: Long,           // API 账号 UID
        val bindTime: Long,         // 绑定时间戳
        var lastLoginTime: Long = 0, // 最后登录时间戳
        var apiUsername: String? = null, // API 账号用户名
        var backupPasswordHash: String? = null, // 备用密码哈希
        var playerName: String? = null // Minecraft 游戏名
    )
    
    /**
     * UID 封禁信息
     */
    data class UidBanData(
        val banUntil: Long,
        val reason: String?
    )
    
    /**
     * 数据存储结构
     */
    data class StorageData(
        val players: MutableMap<String, PlayerData> = mutableMapOf(),
        val welcomes: MutableMap<String, String> = mutableMapOf(),
        val tempAccounts: MutableMap<String, String> = mutableMapOf(),
        val backupPermissions: MutableSet<String> = mutableSetOf(),
        val bannedUids: MutableMap<String, UidBanData> = mutableMapOf()
    )
    
    /**
     * 加载玩家数据
     */
    fun load() {
        if (dataFile.exists()) {
            try {
                val type = object : TypeToken<StorageData>() {}.type
                val data: StorageData = gson.fromJson(dataFile.readText(), type) ?: StorageData()
                playerBindings.clear()
                playerBindings.putAll(data.players)
                welcomeMessages.clear()
                welcomeMessages.putAll(data.welcomes)
                tempAccounts.clear()
                tempAccounts.putAll(data.tempAccounts)
                backupPermissions.clear()
                backupPermissions.addAll(data.backupPermissions)
                // 加载 UID 封禁数据到 LoginManager
                LoginManager.loadBannedUids(data.bannedUids)
                Ohc_login.logger.info("已加载 ${playerBindings.size} 个玩家绑定数据，${tempAccounts.size} 个临时账号，${backupPermissions.size} 个存档权限，${data.bannedUids.size} 个 UID 封禁")
                // 同步到 WelcomeManager
                WelcomeManager.loadFromData(welcomeMessages)
            } catch (e: Exception) {
                Ohc_login.logger.error("加载玩家数据失败: ${e.message}")
            }
        }
    }
    
    /**
     * 保存玩家数据
     */
    fun save() {
        try {
            dataFile.parentFile?.mkdirs()
            // 从 WelcomeManager 获取最新数据
            welcomeMessages.clear()
            welcomeMessages.putAll(WelcomeManager.getDataForSave())
            // 从 LoginManager 获取 UID 封禁数据
            val bannedUids = LoginManager.getBannedUidsForSave()
            val data = StorageData(playerBindings, welcomeMessages, tempAccounts, backupPermissions, bannedUids)
            dataFile.writeText(gson.toJson(data))
        } catch (e: Exception) {
            Ohc_login.logger.error("保存玩家数据失败: ${e.message}")
        }
    }
    
    /**
     * 检查玩家是否已绑定账号
     * @param uuid 玩家 UUID
     * @return 是否已绑定
     */
    fun isBound(uuid: UUID): Boolean {
        return playerBindings.containsKey(uuid.toString())
    }
    
    /**
     * 获取玩家绑定数据
     * @param uuid 玩家 UUID
     * @return 玩家数据，如果未绑定则返回 null
     */
    fun getPlayerData(uuid: UUID): PlayerData? {
        return playerBindings[uuid.toString()]
    }
    
    /**
     * 绑定玩家账号
     * @param uuid 玩家 UUID
     * @param apiUid API 账号 UID
     * @param apiUsername API 账号用户名（可选）
     */
    fun bindPlayer(uuid: UUID, apiUid: Long, apiUsername: String? = null, playerName: String? = null) {
        val data = PlayerData(
            uuid = uuid.toString(),
            apiUid = apiUid,
            bindTime = System.currentTimeMillis(),
            lastLoginTime = System.currentTimeMillis(),
            apiUsername = apiUsername,
            playerName = playerName
        )
        playerBindings[uuid.toString()] = data
        save()
        Ohc_login.logger.info("玩家 $uuid ($playerName) 已绑定到 API 账号 $apiUid (用户名: $apiUsername)")
    }
    
    /**
     * 解绑玩家账号
     * @param uuid 玩家 UUID
     * @return 是否成功解绑
     */
    fun unbindPlayer(uuid: UUID): Boolean {
        val removed = playerBindings.remove(uuid.toString())
        if (removed != null) {
            save()
            Ohc_login.logger.info("玩家 $uuid 已解绑")
            return true
        }
        return false
    }
    
    /**
     * 更新玩家最后登录时间
     * @param uuid 玩家 UUID
     */
    fun updateLastLoginTime(uuid: UUID) {
        playerBindings[uuid.toString()]?.let {
            playerBindings[uuid.toString()] = it.copy(lastLoginTime = System.currentTimeMillis())
            save()
        }
    }
    
    /**
     * 更新玩家 API 用户名
     * @param uuid 玩家 UUID
     * @param apiUsername API 账号用户名
     */
    fun updateApiUsername(uuid: UUID, apiUsername: String) {
        playerBindings[uuid.toString()]?.let {
            playerBindings[uuid.toString()] = it.copy(apiUsername = apiUsername)
            save()
            Ohc_login.logger.info("玩家 $uuid 的 API 用户名已更新为: $apiUsername")
        }
    }
    
    /**
     * 更新玩家游戏名
     * @param uuid 玩家 UUID
     * @param playerName Minecraft 游戏名
     */
    fun updatePlayerName(uuid: UUID, playerName: String) {
        playerBindings[uuid.toString()]?.let {
            if (it.playerName != playerName) {
                playerBindings[uuid.toString()] = it.copy(playerName = playerName)
                save()
                Ohc_login.logger.info("玩家 $uuid 的游戏名已更新为: $playerName")
            }
        }
    }
    
    /**
     * 获取绑定到指定 API UID 的所有玩家 UUID
     * @param apiUid API 账号 UID
     * @return 玩家 UUID 列表
     */
    fun getPlayersByApiUid(apiUid: Long): List<UUID> {
        return playerBindings.entries
            .filter { it.value.apiUid == apiUid }
            .mapNotNull { runCatching { UUID.fromString(it.key) }.getOrNull() }
    }
    
    /**
     * 获取指定 UID 的绑定数量
     */
    fun getBindCountByApiUid(apiUid: Long): Int {
        return playerBindings.values.count { it.apiUid == apiUid }
    }
    
    /**
     * 根据玩家名查找绑定数据
     */
    fun getPlayerDataByName(server: net.minecraft.server.MinecraftServer, playerName: String): PlayerData? {
        val uuid = server.playerManager.getPlayer(playerName)?.uuid
            ?: findUuidByName(playerName)
            ?: return null
        return getPlayerData(uuid)
    }
    
    /**
     * 根据玩家名查找 UUID（从已绑定的玩家数据中查找）
     */
    fun findUuidByName(playerName: String): java.util.UUID? {
        // 从已绑定的玩家数据中查找（优先匹配游戏名，其次匹配 API 用户名）
        for ((uuidStr, data) in playerBindings) {
            if (data.playerName?.equals(playerName, ignoreCase = true) == true ||
                data.apiUsername?.equals(playerName, ignoreCase = true) == true) {
                return try { java.util.UUID.fromString(uuidStr) } catch (e: Exception) { null }
            }
        }
        return null
    }
    
    /**
     * 根据 UUID 查找玩家名（从已绑定的玩家数据中查找）
     */
    fun findNameByUuid(uuid: java.util.UUID): String? {
        return playerBindings[uuid.toString()]?.apiUsername
    }
    
    /**
     * 获取所有绑定数据
     */
    fun getAllBindings(): Map<String, PlayerData> = playerBindings.toMap()
    
    /**
     * 设置玩家备用密码
     * @param uuid 玩家 UUID
     * @param passwordHash 密码哈希（SHA-256）
     * @return 是否成功
     */
    fun setBackupPassword(uuid: java.util.UUID, passwordHash: String): Boolean {
        val data = playerBindings[uuid.toString()] ?: return false
        playerBindings[uuid.toString()] = data.copy(backupPasswordHash = passwordHash)
        save()
        return true
    }
    
    /**
     * 删除玩家备用密码
     * @param uuid 玩家 UUID
     * @return 是否成功
     */
    fun removeBackupPassword(uuid: java.util.UUID): Boolean {
        val data = playerBindings[uuid.toString()] ?: return false
        if (data.backupPasswordHash == null) return false
        playerBindings[uuid.toString()] = data.copy(backupPasswordHash = null)
        save()
        return true
    }
    
    /**
     * 检查玩家是否设置了备用密码
     * @param uuid 玩家 UUID
     */
    fun hasBackupPassword(uuid: java.util.UUID): Boolean {
        return playerBindings[uuid.toString()]?.backupPasswordHash != null
    }
    
    /**
     * 验证备用密码
     * @param uuid 玩家 UUID
     * @param passwordHash 密码哈希
     * @return 是否匹配
     */
    fun verifyBackupPassword(uuid: java.util.UUID, passwordHash: String): Boolean {
        val data = playerBindings[uuid.toString()] ?: return false
        return data.backupPasswordHash == passwordHash
    }
    
    // ==================== 临时账号管理 ====================
    
    /**
     * 创建临时账号（未绑定玩家设置备用密码）
     */
    fun createTempAccount(uuid: UUID, passwordHash: String): Boolean {
        tempAccounts[uuid.toString()] = passwordHash
        save()
        Ohc_login.logger.info("玩家 $uuid 创建了临时账号")
        return true
    }
    
    /**
     * 检查玩家是否有临时账号
     */
    fun hasTempAccount(uuid: UUID): Boolean {
        return tempAccounts.containsKey(uuid.toString())
    }
    
    /**
     * 验证临时账号密码
     */
    fun verifyTempPassword(uuid: UUID, passwordHash: String): Boolean {
        return tempAccounts[uuid.toString()] == passwordHash
    }
    
    /**
     * 删除临时账号（绑定正式账号后调用）
     */
    fun removeTempAccount(uuid: UUID): Boolean {
        val removed = tempAccounts.remove(uuid.toString())
        if (removed != null) {
            save()
            Ohc_login.logger.info("玩家 $uuid 的临时账号已删除")
            return true
        }
        return false
    }
    
    /**
     * 修改临时账号密码
     */
    fun updateTempPassword(uuid: UUID, newPasswordHash: String): Boolean {
        if (!tempAccounts.containsKey(uuid.toString())) return false
        tempAccounts[uuid.toString()] = newPasswordHash
        save()
        return true
    }
    
    /**
     * 检查玩家是否有存档权限
     */
    fun hasBackupPermission(playerName: String): Boolean {
        return backupPermissions.contains(playerName.lowercase())
    }
    
    /**
     * 授予玩家存档权限
     */
    fun grantBackupPermission(playerName: String): Boolean {
        val name = playerName.lowercase()
        if (backupPermissions.contains(name)) return false
        backupPermissions.add(name)
        save()
        return true
    }
    
    /**
     * 撤销玩家存档权限
     */
    fun revokeBackupPermission(playerName: String): Boolean {
        val name = playerName.lowercase()
        if (!backupPermissions.contains(name)) return false
        backupPermissions.remove(name)
        save()
        return true
    }
    
    /**
     * 获取所有有存档权限的玩家
     */
    fun getBackupPermissionList(): Set<String> {
        return backupPermissions.toSet()
    }
}
